import java.io.*;
import java.util.*;

public class MetaTest extends Object {
	private static File file;
	private static FileReader input;
	private static StreamTokenizer st;
	private static MetaPackage metaPackage;
	private static MetaClass metaClass;
	private static LinkedList<String> list;
	
	public static void main(String[] args) throws Exception {
		/*
		 * Should I store previous to figure out the attribute name when "=" is scanned?
		 */
		
		file = new File("MetaParseTestFile.java");
		input = new FileReader(file);
		st = new StreamTokenizer(input);
		st.slashSlashComments(true);
		st.slashStarComments(true);
		st.nextToken();
		metaPackage = new MetaPackage();
		list = new LinkedList<String>();
		
		while (st.ttype != StreamTokenizer.TT_EOF) {
			checkMetaValue();
		}
		if (metaClass != null)
			metaPackage.addClass(metaClass);
		
		printToken();
	}
	
	public static void checkMetaValue() throws Exception {
		if (checkTokenType() == "word" && 
				(st.sval.equals("public") || st.sval.equals("protected") || st.sval.equals("private"))) {
			// Adds modifier (modifier)
			list.add(st.sval);
			confirmMetaValue();
		}
		else if (checkTokenType() == "word" && st.sval.equals("package")) {
			addPackage();
		}
		else if (checkTokenType() == "word" && st.sval.equals("class")) {
			list.add("default");
			list.add(st.sval);
			isClass();
		}
		else if (checkTokenType() == "word" && st.sval.equals("static")) {
			list.add("default");
			list.add(st.sval);
			isStatic();
		}
		else {
			st.nextToken();
		}
	}
	
	public static void addPackage() throws Exception {
		// Add package name 
		st.nextToken();
		metaPackage.setPackageName(st.sval);
		//Run to next token for next phase
		st.nextToken();
	}
	
	public static void confirmMetaValue() throws Exception {
		st.nextToken();
		if (checkTokenType() == "word" && st.sval.equals("class")) {
			// Adds "class" (class)
			list.add(st.sval);
			isClass();
		}
		else if (checkTokenType() == "word" && st.sval.equals("static")) {
			// Adds "static" (static)
			list.add(st.sval);
			isStatic();
		}
		else {
			checkMethodAttribute();
		}
	}
	
	public static String checkTokenType() throws Exception {
		String tokenType;
		// This is the switch loop to figure out if it is a word, number, or char
		switch (st.ttype) {
    		case StreamTokenizer.TT_WORD:
    			tokenType = "word";
//    			System.out.println(st.sval);
//    			if (st.sval.equals("import")) 
//    				System.out.println("true1");
    			break;
    		case StreamTokenizer.TT_NUMBER:
    			tokenType = "number";
//    			System.out.println(st.nval);
//    			if (st.nval == 1)
//    				System.out.println("true number!!!!!!!!!!!!");
    			break;
    		default: {
    			tokenType = "char";
//    			System.out.println((char) st.ttype);
//    			if ((char) st.ttype == ';') 
//    				System.out.println("true************************");
    			break;
    		}
		}
		return tokenType;
	}
	
	public static void isStatic() throws Exception {
		// Move to next value
		st.nextToken();
		if (checkTokenType() == "word" && 
				(st.sval.equals("public") || st.sval.equals("protected") || st.sval.equals("private"))) {
			// Adds modifier (modifier)
			list.remove(0);
			list.add(0,st.sval);
			st.nextToken();
		}

		checkMethodAttribute();
	}
	
	public static void checkMethodAttribute() throws Exception {
		if (checkTokenType() == "word" && st.sval.equals("final")) {
			// Adds "final" (constant)
			list.add(st.sval);
			st.nextToken();
		}
		// Add first value (type)
		String firstVal = "";
		firstVal += st.sval;
		st.nextToken();
		// Generic type check
		if (checkTokenType() == "char" && (char)st.ttype == '<') {
			firstVal += (char)st.ttype;
			st.nextToken();
			firstVal += st.sval;
			st.nextToken();
			firstVal += (char)st.ttype;
			// Proceed to second value
			st.nextToken();
		}
		list.add(firstVal);
		
		// Constructor Check
		if (checkTokenType() == "char" && (char)st.ttype == '(') {
			list.clear();
			return;
		}
		
		// Add second value (name)
		list.add(st.sval);
		
		// Check whether it is a method or attribute
		st.nextToken();
		if (checkTokenType() == "char" && (char)st.ttype == '(') {
			// Method
			MetaMethod m = new MetaMethod();
			m.setName(list.pollLast());
			m.setReturnType(list.pollLast());
			if (list.peekLast().equals("static"))
				m.setStatic(list.pollLast());
			m.setModifier(list.pollLast());
			metaClass.addMethod(m);
		}
		else {
			// Attribute
			MetaAttribute a = new MetaAttribute();
			a.setName(list.pollLast());
			a.setType(list.pollLast());
			if (list.peekLast().equals("final"))
				a.setFinal(list.pollLast());
			if (list.peekLast().equals("static"))
				a.setStatic(list.pollLast());
			a.setModifier(list.pollLast());
			metaClass.addAttribute(a);
		}
	}
	
	public static void isClass() throws Exception {
		if (metaClass != null)
			metaPackage.addClass(metaClass);
		metaClass = new MetaClass();
		st.nextToken();
//		System.out.println(st.sval); //**********************************************
		// Adds class name
		list.add(st.sval);
		//metaClass.setClassName(st.sval);
		st.nextToken();
//		System.out.println(st.sval); //**********************************************
		if (checkTokenType() == "word" && st.sval.equals("extends")) {
			st.nextToken();
//			System.out.println(st.sval); //**********************************************
			// Adds super class name
			list.add(st.sval);
			metaClass.setSuperClassName(list.pollLast());
			
			// Move on to next token after superclass name
			st.nextToken();
		}
		// Set class name
		metaClass.setClassName(list.pollLast());
		// Poll "class"
		list.pollLast();
		// Pop modifier
		metaClass.setClassModifier(list.pollLast());
	}
	
	public static void nextToken(String token) throws Exception {
		st.nextToken();
	}
	
	public static void printToken() {
		System.out.println(metaPackage.toString());
	}
}